/*
 * Node.cpp
 *
 *  Created on: Jul 2, 2013
 *      Author: dsweeney
 */
#include "Node.h"
#include "CommonTypes.h"
#include "LoggerSingleton.h"
#include <string>
#include <map>
#include <iostream>
#include <string.h>
#include <ctype.h>
///////////////////////////////////////////////////////////////////////////////
uint Node::id = 0;
std::map<char, int> Node::charToPoint;
std::string Node::fullSet;
///////////////////////////////////////////////////////////////////////////////
Node::Node(char c)
{
	this->parent = NULL;
	this->letter = tolower(c);
	this->init();
}
///////////////////////////////////////////////////////////////////////////////
Node::Node(char c, Node* parent)
{
	this->letter = tolower(c);
	this->parent = parent;
	this->init();
}
///////////////////////////////////////////////////////////////////////////////
void Node::reInit()
{
	//reInit all the children
	for(int i = 0; i < 26; i++)
		if(this->children[i] != NULL)
			this->children[i]->reInit();

	if(this->listOfChildren != NULL && this->listOfChildren != &(Node::fullSet))
	{
		delete this->listOfChildren;
		this->listOfChildren = NULL;
	}

	index = 0;
	explored = false;
	wholeWord = false;
	fullSetInUse = false;
}
///////////////////////////////////////////////////////////////////////////////
void Node::init()
{
	id++;
	explored = false;
	wholeWord = false;
	this->lowercaseAoffset = 97;
	lastGet = 0;
	numChildren = 0;
	listOfChildren = NULL;
	index = 0;
	fullSetInUse = false;

	memset((void*)children, 0, sizeof(p_Node)*26);

	if(charToPoint.empty())
	{
		charToPoint['a'] = 1;
		charToPoint['b'] = 3;
		charToPoint['c'] = 3;
		charToPoint['d'] = 2;
		charToPoint['e'] = 1;
		charToPoint['f'] = 4;
		charToPoint['g'] = 2;
		charToPoint['h'] = 4;
		charToPoint['i'] = 1;
		charToPoint['j'] = 8;
		charToPoint['k'] = 5;
		charToPoint['l'] = 1;
		charToPoint['m'] = 3;
		charToPoint['n'] = 1;
		charToPoint['o'] = 1;
		charToPoint['p'] = 3;
		charToPoint['q'] = 10;
		charToPoint['r'] = 1;
		charToPoint['s'] = 1;
		charToPoint['t'] = 1;
		charToPoint['u'] = 1;
		charToPoint['v'] = 4;
		charToPoint['w'] = 4;
		charToPoint['x'] = 8;
		charToPoint['y'] = 4;
		charToPoint['z'] = 10;
		charToPoint['_'] = 0;
	}


	this->rawScore = this->parent != NULL ?
		this->parent->getScore() + charToPoint[letter] :
		charToPoint[letter];
}
///////////////////////////////////////////////////////////////////////////////
Node::~Node()
{
	//release all the children
	for(int i = 0; i < 26; i++)
	{
		if(this->children[i] != NULL)
		{
			delete this->children[i];
			id--;
			//Logger::instance()->write(__FILE__, __LINE__, (int)id);
		}
	}

	if(this->listOfChildren != NULL)
		delete this->listOfChildren;
}
///////////////////////////////////////////////////////////////////////////////
bool Node::addChild(char letter)
{
	int value = tolower(letter) - lowercaseAoffset;
	//assumed this is going to be used only when the graph is being built.
	//therefore will only be called in the process of building whole words,
	//so me thinks it is ok to just increment anytime this is called.
	this->numChildren++;

	if(value > -1 && value < 26 && (this->children[value] == NULL))
	{
		this->children[value] =
				new Node(tolower(letter), this);
		return true;
	}

	return false;
}
///////////////////////////////////////////////////////////////////////////////
Node* Node::getChild(char letter)
{
	int value = tolower(letter) - lowercaseAoffset;

	if(value > -1 &&  value < 26)
	{
		this->lastGet = value;
		return (Node*) this->children[value];
	}
	else
		return NULL;
}
///////////////////////////////////////////////////////////////////////////////
Node* Node::getNextChild()
{
	Node* child = NULL;
	std::string* listInUse = this->fullSetInUse == true?
			&(Node::fullSet):
			this->listOfChildren;

	for(; (index < listInUse->length()) && (child == NULL); index++)
	{
		char current = listInUse->at(index);

		if(current >= 'a' && current <= 'z')
			child = this->children[current - lowercaseAoffset];
		else if (current == '_')
		{
			this->fullSetInUse = true;
			listInUse = &(Node::fullSet);
			this->index = -1;
		}
		else
			LOG(__FILE__, __LINE__, "invalid character handled");

		//prevent us from re-doing states in the event of a wildcard
		if(child != NULL && child->explored == true)
			child = NULL;
	}

	if(child != NULL)
	{
		child->listCopy(this->listOfChildren->c_str());
		child->explored = true;
	}

	return child;
}
///////////////////////////////////////////////////////////////////////////////
uint Node::getScore()
{
	return this->rawScore;
}
///////////////////////////////////////////////////////////////////////////////
void Node::getString(std::string* string)
//to recurse to not to recurse?
//i recursed...
{
	if(this->letter != ' ')
	{
		string->insert(0, 1, this->letter);
		this->parent->getString(string);
	}
	else
		return;
}
///////////////////////////////////////////////////////////////////////////////
char Node::getLetter()
{
	return this->letter;
}
///////////////////////////////////////////////////////////////////////////////
uint Node::numWholeWordChildren()
{
	return this->numChildren;
}
///////////////////////////////////////////////////////////////////////////////
void Node::listCopy(const char* source)
{
	int location;

	if(this->listOfChildren != NULL)
	{
		LOG(__FILE__, __LINE__, "tried to assign list twice");
		delete this->listOfChildren;
	}

	this->listOfChildren = new std::string (source);

	if(this->parent->fullSetInUse)
		location = listOfChildren->find('_');
	else
		location = listOfChildren->find(this->letter);

	if(location != -1)
		listOfChildren->erase(location, 1);

	//LOG(__FILE__, __LINE__, *(this->listOfChildren));
}
///////////////////////////////////////////////////////////////////////////////
